"""
简化的视频流处理服务
Simplified Video Stream Processing Service

提供视频流处理的核心功能：
- 视频帧提取和处理
- 视频流解析和格式转换
- 基本的流状态管理
- 简化的错误处理和重试机制
"""
import asyncio
import logging
import time
from typing import Optional, Dict, Any, List, AsyncGenerator, Tuple
from datetime import datetime, timedelta
from dataclasses import dataclass
from enum import Enum
import cv2
import numpy as np
from contextlib import asynccontextmanager

from config.settings import settings

logger = logging.getLogger(__name__)


class StreamStatus(str, Enum):
    """视频流状态枚举"""
    STOPPED = "stopped"
    STARTING = "starting"
    RUNNING = "running"
    ERROR = "error"
    RECONNECTING = "reconnecting"


class VideoFormat(str, Enum):
    """视频格式枚举"""
    FLV = "flv"
    HLS = "hls"
    RTMP = "rtmp"
    RTSP = "rtsp"
    WEBRTC = "webrtc"


@dataclass
class StreamInfo:
    """视频流信息"""
    camera_id: str
    stream_url: str
    format: VideoFormat
    width: int = 0
    height: int = 0
    fps: float = 0.0
    bitrate: int = 0
    status: StreamStatus = StreamStatus.STOPPED
    last_frame_time: Optional[datetime] = None
    error_message: Optional[str] = None


@dataclass
class FrameData:
    """视频帧数据"""
    camera_id: str
    frame: np.ndarray
    timestamp: datetime
    frame_number: int
    width: int
    height: int


class VideoFrameExtractor:
    """简化的视频帧提取器"""
    
    def __init__(self, stream_url: str, camera_id: str, target_fps: int = None):
        self.stream_url = stream_url
        self.camera_id = camera_id
        self.target_fps = target_fps or settings.VIDEO_PROCESSING_FPS
        self.frame_interval = 1.0 / self.target_fps
        
        self.cap: Optional[cv2.VideoCapture] = None
        self.is_running = False
        self.last_frame_time = 0
        self.frame_count = 0
        self.reconnect_attempts = 0
        self.max_reconnect_attempts = 3
        
        # 性能统计
        self.stats = {
            "frames_extracted": 0,
            "frames_dropped": 0,
            "reconnections": 0,
            "start_time": None,
            "last_frame_timestamp": None
        }
    
    async def start(self) -> bool:
        """启动视频流捕获"""
        try:
            logger.info(f"启动视频流捕获: {self.camera_id}")
            
            # 创建OpenCV捕获对象
            self.cap = cv2.VideoCapture(self.stream_url)
            
            # 设置基本参数
            self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)  # 减少缓冲延迟
            self.cap.set(cv2.CAP_PROP_FPS, self.target_fps)
            
            # 测试连接
            if not self.cap.isOpened():
                logger.error(f"无法打开视频流: {self.camera_id}")
                return False
            
            # 尝试读取一帧验证
            ret, frame = self.cap.read()
            if not ret or frame is None:
                logger.error(f"无法读取视频帧: {self.camera_id}")
                return False
            
            self.is_running = True
            self.reconnect_attempts = 0
            self.stats["start_time"] = datetime.now()
            
            logger.info(f"视频流启动成功: {self.camera_id}")
            return True
            
        except Exception as e:
            logger.error(f"启动视频流失败: {self.camera_id} - {e}")
            return False
    
    async def stop(self):
        """停止视频流捕获"""
        try:
            self.is_running = False
            if self.cap:
                self.cap.release()
                self.cap = None
            logger.info(f"视频流已停止: {self.camera_id}")
        except Exception as e:
            logger.error(f"停止视频流失败: {self.camera_id} - {e}")
    
    async def extract_frame(self) -> Optional[FrameData]:
        """提取单帧视频数据"""
        if not self.is_running or not self.cap:
            return None
        
        try:
            # 控制帧率
            current_time = time.time()
            if current_time - self.last_frame_time < self.frame_interval:
                return None
            
            # 读取帧
            ret, frame = self.cap.read()
            if not ret or frame is None:
                logger.warning(f"读取帧失败: {self.camera_id}")
                return None
            
            # 更新统计
            self.last_frame_time = current_time
            self.frame_count += 1
            self.stats["frames_extracted"] += 1
            self.stats["last_frame_timestamp"] = datetime.now()
            
            # 创建帧数据
            height, width = frame.shape[:2]
            frame_data = FrameData(
                camera_id=self.camera_id,
                frame=frame,
                timestamp=datetime.now(),
                frame_number=self.frame_count,
                width=width,
                height=height
            )
            
            return frame_data
            
        except Exception as e:
            logger.error(f"提取帧异常: {self.camera_id} - {e}")
            return None
    
    async def extract_frames(self) -> AsyncGenerator[FrameData, None]:
        """持续提取视频帧的异步生成器"""
        while self.is_running:
            try:
                frame_data = await self.extract_frame()
                if frame_data:
                    yield frame_data
                else:
                    # 短暂等待避免CPU占用过高
                    await asyncio.sleep(0.01)
                    
            except Exception as e:
                logger.error(f"帧提取循环异常: {self.camera_id} - {e}")
                await asyncio.sleep(1)
    
    def get_stream_info(self) -> Dict[str, Any]:
        """获取视频流信息"""
        info = {
            "camera_id": self.camera_id,
            "stream_url": self.stream_url,
            "is_running": self.is_running,
            "target_fps": self.target_fps,
            "frame_count": self.frame_count,
            "stats": self.stats.copy()
        }
        
        if self.cap and self.cap.isOpened():
            try:
                info.update({
                    "width": int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
                    "height": int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)),
                    "actual_fps": self.cap.get(cv2.CAP_PROP_FPS)
                })
            except Exception:
                pass
        
        return info


class VideoService:
    """简化的视频流处理服务"""
    
    def __init__(self):
        self.active_extractors: Dict[str, VideoFrameExtractor] = {}
        self.stream_info: Dict[str, StreamInfo] = {}
        self.processing_tasks: Dict[str, asyncio.Task] = {}
        
        # 简单的内存缓存
        self._url_cache: Dict[str, Dict[str, Any]] = {}
        self._cache_ttl = 300  # 5分钟缓存
    
    async def get_stream_url(self, camera_id: str, format_type: str = "flv") -> Optional[str]:
        """获取视频流播放地址"""
        try:
            # 检查缓存
            cache_key = f"{camera_id}_{format_type}"
            if cache_key in self._url_cache:
                cached_data = self._url_cache[cache_key]
                if datetime.now() < cached_data["expires_at"]:
                    logger.debug(f"返回缓存的流地址: {camera_id}")
                    return cached_data["url"]
            
            # 这里应该调用WVP服务获取真实的流地址
            # 为了简化，我们先返回一个模拟地址
            from core.wvp_service import get_wvp_service
            
            wvp_service = get_wvp_service()
            play_info = await wvp_service.get_play_url(camera_id, format_type=format_type)
            
            if play_info and play_info.play_url:
                stream_url = play_info.play_url
                
                # 缓存结果
                self._url_cache[cache_key] = {
                    "url": stream_url,
                    "expires_at": datetime.now() + timedelta(seconds=self._cache_ttl)
                }
                
                logger.info(f"获取到流地址: {camera_id} -> {stream_url}")
                return stream_url
            else:
                logger.warning(f"无法获取摄像头流地址: {camera_id}")
                return None
                
        except Exception as e:
            logger.error(f"获取流地址异常: {camera_id} - {e}")
            return None
    
    async def start_stream_processing(self, camera_id: str, stream_url: Optional[str] = None) -> bool:
        """启动视频流处理"""
        try:
            # 如果已经在处理，先停止
            if camera_id in self.active_extractors:
                await self.stop_stream_processing(camera_id)
            
            # 获取流地址
            if not stream_url:
                stream_url = await self.get_stream_url(camera_id)
                if not stream_url:
                    logger.error(f"无法获取流地址: {camera_id}")
                    return False
            
            # 创建帧提取器
            extractor = VideoFrameExtractor(
                stream_url=stream_url,
                camera_id=camera_id,
                target_fps=settings.VIDEO_PROCESSING_FPS
            )
            
            # 启动提取器
            if not await extractor.start():
                logger.error(f"启动帧提取器失败: {camera_id}")
                return False
            
            # 保存提取器
            self.active_extractors[camera_id] = extractor
            
            # 创建流信息
            self.stream_info[camera_id] = StreamInfo(
                camera_id=camera_id,
                stream_url=stream_url,
                format=VideoFormat.FLV,  # 默认格式
                status=StreamStatus.RUNNING,
                last_frame_time=datetime.now()
            )
            
            logger.info(f"视频流处理启动成功: {camera_id}")
            return True
            
        except Exception as e:
            logger.error(f"启动视频流处理异常: {camera_id} - {e}")
            return False
    
    async def stop_stream_processing(self, camera_id: str) -> bool:
        """停止视频流处理"""
        try:
            # 停止帧提取器
            if camera_id in self.active_extractors:
                extractor = self.active_extractors[camera_id]
                await extractor.stop()
                del self.active_extractors[camera_id]
            
            # 停止处理任务
            if camera_id in self.processing_tasks:
                task = self.processing_tasks[camera_id]
                if not task.done():
                    task.cancel()
                del self.processing_tasks[camera_id]
            
            # 更新流信息
            if camera_id in self.stream_info:
                self.stream_info[camera_id].status = StreamStatus.STOPPED
            
            logger.info(f"视频流处理已停止: {camera_id}")
            return True
            
        except Exception as e:
            logger.error(f"停止视频流处理异常: {camera_id} - {e}")
            return False
    
    async def extract_frame(self, camera_id: str) -> Optional[FrameData]:
        """提取单帧数据"""
        try:
            if camera_id not in self.active_extractors:
                logger.warning(f"摄像头未启动流处理: {camera_id}")
                return None
            
            extractor = self.active_extractors[camera_id]
            frame_data = await extractor.extract_frame()
            
            # 更新流信息
            if frame_data and camera_id in self.stream_info:
                stream_info = self.stream_info[camera_id]
                stream_info.last_frame_time = frame_data.timestamp
                stream_info.width = frame_data.width
                stream_info.height = frame_data.height
            
            return frame_data
            
        except Exception as e:
            logger.error(f"提取帧数据异常: {camera_id} - {e}")
            return None
    
    async def process_frame_with_ai(self, frame_data: FrameData, ai_services: List[str] = None) -> Dict[str, Any]:
        """使用AI服务处理视频帧"""
        try:
            results = {
                "camera_id": frame_data.camera_id,
                "timestamp": frame_data.timestamp.isoformat(),
                "frame_number": frame_data.frame_number,
                "ai_results": {}
            }
            
            # 这里将在后续任务中集成AI服务
            # 目前返回基本的帧信息
            if ai_services:
                for service_name in ai_services:
                    # 模拟AI处理结果
                    results["ai_results"][service_name] = {
                        "status": "processed",
                        "confidence": 0.85,
                        "processing_time": 0.1
                    }
            
            return results
            
        except Exception as e:
            logger.error(f"AI处理帧数据异常: {frame_data.camera_id} - {e}")
            return {
                "camera_id": frame_data.camera_id,
                "error": str(e)
            }
    
    async def convert_frame_format(self, frame_data: FrameData, target_format: str = "jpg") -> Optional[bytes]:
        """转换帧格式"""
        try:
            if target_format.lower() == "jpg":
                success, encoded_frame = cv2.imencode('.jpg', frame_data.frame)
                if success:
                    return encoded_frame.tobytes()
            elif target_format.lower() == "png":
                success, encoded_frame = cv2.imencode('.png', frame_data.frame)
                if success:
                    return encoded_frame.tobytes()
            else:
                logger.warning(f"不支持的格式: {target_format}")
                return None
            
            return None
            
        except Exception as e:
            logger.error(f"转换帧格式异常: {frame_data.camera_id} - {e}")
            return None
    
    def get_stream_info(self, camera_id: str) -> Optional[StreamInfo]:
        """获取视频流信息"""
        return self.stream_info.get(camera_id)
    
    def get_all_streams_info(self) -> Dict[str, StreamInfo]:
        """获取所有视频流信息"""
        return self.stream_info.copy()
    
    def get_active_streams(self) -> List[str]:
        """获取活跃的视频流列表"""
        return list(self.active_extractors.keys())
    
    def get_stream_statistics(self, camera_id: str) -> Optional[Dict[str, Any]]:
        """获取视频流统计信息"""
        if camera_id in self.active_extractors:
            extractor = self.active_extractors[camera_id]
            return extractor.get_stream_info()
        return None
    
    async def test_stream_connection(self, camera_id: str, stream_url: Optional[str] = None) -> Dict[str, Any]:
        """测试视频流连接"""
        try:
            # 获取流地址
            if not stream_url:
                stream_url = await self.get_stream_url(camera_id)
                if not stream_url:
                    return {
                        "success": False,
                        "message": "无法获取流地址"
                    }
            
            # 创建临时提取器测试连接
            test_extractor = VideoFrameExtractor(
                stream_url=stream_url,
                camera_id=f"test_{camera_id}",
                target_fps=1
            )
            
            # 测试启动
            if await test_extractor.start():
                # 尝试提取一帧
                frame_data = await test_extractor.extract_frame()
                await test_extractor.stop()
                
                if frame_data:
                    return {
                        "success": True,
                        "message": "视频流连接正常",
                        "stream_url": stream_url,
                        "width": frame_data.width,
                        "height": frame_data.height
                    }
                else:
                    return {
                        "success": False,
                        "message": "无法提取视频帧"
                    }
            else:
                return {
                    "success": False,
                    "message": "无法连接视频流"
                }
                
        except Exception as e:
            return {
                "success": False,
                "message": f"测试连接异常: {e}"
            }
    
    async def cleanup(self):
        """清理资源"""
        try:
            # 停止所有活跃的流处理
            camera_ids = list(self.active_extractors.keys())
            for camera_id in camera_ids:
                await self.stop_stream_processing(camera_id)
            
            # 清空缓存
            self._url_cache.clear()
            
            logger.info("视频服务资源清理完成")
            
        except Exception as e:
            logger.error(f"清理视频服务资源异常: {e}")


# 全局视频服务实例
_video_service: Optional[VideoService] = None


def get_video_service() -> VideoService:
    """获取视频服务实例"""
    global _video_service
    if _video_service is None:
        _video_service = VideoService()
    return _video_service


# 便捷的上下文管理器
@asynccontextmanager
async def video_stream_context(camera_id: str, stream_url: Optional[str] = None):
    """视频流处理上下文管理器"""
    video_service = get_video_service()
    
    try:
        # 启动流处理
        success = await video_service.start_stream_processing(camera_id, stream_url)
        if not success:
            raise RuntimeError(f"启动视频流处理失败: {camera_id}")
        
        yield video_service
        
    finally:
        # 确保停止流处理
        await video_service.stop_stream_processing(camera_id)